package cn.bjit.service.impl;

import cn.bjit.config.RabbitMQConfig;
import cn.bjit.enums.BizCodeEnum;
import cn.bjit.enums.CouponStateEnum;
import cn.bjit.enums.ProductOrderStateEnum;
import cn.bjit.enums.StockTaskStateEnum;
import cn.bjit.exception.BizException;
import cn.bjit.feign.ProductOrderFeignService;
import cn.bjit.interceptor.LoginInterceptor;
import cn.bjit.mapper.CouponRecordMapper;
import cn.bjit.mapper.CouponTaskMapper;
import cn.bjit.model.*;
import cn.bjit.request.LockCouponRecordRequest;
import cn.bjit.service.CouponRecordService;
import cn.bjit.util.JsonData;
import cn.bjit.vo.CouponRecordVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CouponRecordServiceImpl implements CouponRecordService {
    @Resource
    private CouponRecordMapper couponRecordMapper;
    @Resource
    private CouponTaskMapper couponTaskMapper;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private RabbitMQConfig rabbitMQConfig;
    @Resource
    private ProductOrderFeignService orderFeignService;

    /**
     * 分页查询优惠券领取记录
     *
     * @param page
     * @param size
     * @return
     */
    public Map<String, Object> page(int page, int size) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        Page<CouponRecordDO> pageInfo = new Page(page, size);

        IPage<CouponRecordDO> recordDOIPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>()
                .eq("user_id", loginUser.getId())//
                .orderByDesc("create_time"));//

        Map<String, Object> pageMap = new HashMap<>();
        pageMap.put("total_record", recordDOIPage.getTotal()); //总记录数
        pageMap.put("total_page", recordDOIPage.getPages());  //总页数
        pageMap.put("current_data", recordDOIPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList())); //一页的数据列表
        return pageMap;
    }


    /**
     * 根据id查询个人优惠券详情
     *
     * @param recordId
     * @return
     */
    public CouponRecordVO findById(long recordId) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        CouponRecordDO couponRecordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>()
                .eq("id", recordId).eq("user_id", loginUser.getId()));
        if (couponRecordDO == null) {
            return null;
        }
        return beanProcess(couponRecordDO);
    }

    /**
     * 锁定优惠券记录
     * 1，锁定优惠券记录
     * 2，task表插入记录
     * 3，发送延迟消息
     *
     * @param lockCouponRecordRequest
     * @return
     */
    public JsonData lockCouponRecords(LockCouponRecordRequest lockCouponRecordRequest) {
        //获取用户
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        //优惠券id列表  获取订单
        List<Long> lockCouponRecordIds = lockCouponRecordRequest.getLockCouponRecords();
        String orderOutTradeNo = lockCouponRecordRequest.getOrderOutTradeNo();
        //1，批量锁定优惠券记录
        int updateRows = couponRecordMapper.lockUserStateBatch(loginUser.getId(), CouponStateEnum.USED.name(), lockCouponRecordIds);

        List<CouponTaskDO> couponTaskDOList = lockCouponRecordIds.stream().map(obj -> {
            CouponTaskDO couponTaskDO = new CouponTaskDO();
            couponTaskDO.setCreateTime(new Date());
            couponTaskDO.setOutTradeNo(orderOutTradeNo);
            couponTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
            return couponTaskDO;
        }).collect(Collectors.toList());
        //2,task表插入记录
        int insertRows = couponTaskMapper.insertBatch(couponTaskDOList);
        log.info("优惠券记录锁定 updateRows={}", updateRows);
        log.info("task表中插入记录task={}", insertRows);
        if (lockCouponRecordIds.size() == insertRows && insertRows == updateRows) {
            //3,发送延迟消息
            for (CouponTaskDO couponTaskDO : couponTaskDOList) {
                CouponRecordMessage couponRecordMessage = new CouponRecordMessage();
                couponRecordMessage.setOutTradeNo(orderOutTradeNo);
                couponRecordMessage.setTaskId(couponTaskDO.getId());

                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);
                log.info("优惠券锁定消息发送成功！{}", couponRecordMessage.toString());
            }

            return JsonData.buildSuccess();
        } else {
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }
    }
    /**
     * 释放优惠券
     * 1，查询工作单记录
     * 2，查询订单的状态
     *
     * @param recordMessage
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean releaseCouponRecord(CouponRecordMessage recordMessage) {
        //1，查询task是否存在
        CouponTaskDO couponTaskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>().eq("id", recordMessage.getTaskId()));
        if (couponTaskDO == null) {
            log.warn("工作单不存在，消息{}", recordMessage);
            return true;
        }
        //如果是Lock状态处理
        if (couponTaskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
            //查询订单 TODO
            JsonData jsonData = orderFeignService.queryProductOrderState(recordMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {
                //查到订单，正常处理，判断订单的状态
                String state = jsonData.getData().toString(); //CANCEL
                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    //如果已支付，则需改为finish
                    couponTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    //根据id修改Coupon_tash的lock_state为FINISH
                    couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", recordMessage.getTaskId()));
                    log.info("订单已经支付，修改库存锁定状态为finish{}", recordMessage);
                    return true;
                }
            }
            //订单不存在，或者订单被取消，则修改状态为CANCEL 并且把优惠券记录修改为NEW
            log.warn("订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL,恢复优惠券使用记录为NEW,message:{}", recordMessage);
            couponTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", recordMessage.getTaskId()));
            //恢复优惠券记录由原来的USED 编程NEW
            couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(), CouponStateEnum.NEW.name());
            return true;
        } else {
            log.warn("工作单状态不是Lock，state={}", couponTaskDO.getLockState(), recordMessage);
            return true;
        }
    }

    private CouponRecordVO beanProcess(CouponRecordDO couponRecordDO) {
        CouponRecordVO couponRecordVO = new CouponRecordVO();
        BeanUtils.copyProperties(couponRecordDO, couponRecordVO);
        return couponRecordVO;
    }

}
